home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gdevvec.c < prev    next >
C/C++ Source or Header  |  1997-05-04  |  26KB  |  862 lines

  1. /* Copyright (C) 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gdevvec.c */
  20. /* Utilities for "vector" devices */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gp.h"
  26. #include "gserrors.h"
  27. #include "gsparam.h"
  28. #include "gsutil.h"
  29. #include "gxfixed.h"
  30. #include "gdevvec.h"
  31. #include "gscspace.h"
  32. #include "gxdcolor.h"
  33. #include "gxpaint.h"        /* requires gx_path, ... */
  34. #include "gzpath.h"
  35. #include "gzcpath.h"
  36.  
  37. /******
  38.  ****** NOTE: EVERYTHING IN THIS FILE IS SUBJECT TO CHANGE WITHOUT NOTICE.
  39.  ****** USE AT YOUR OWN RISK.
  40.  ******/
  41.  
  42. /* Structure descriptors */
  43. public_st_device_vector();
  44. public_st_vector_image_enum();
  45.  
  46. /* ================ Default implementations of vector procs ================ */
  47.  
  48. int
  49. gdev_vector_setflat(gx_device_vector *vdev, floatp flatness)
  50. {    return 0;
  51. }
  52.  
  53. int
  54. gdev_vector_dopath(gx_device_vector *vdev, const gx_path *ppath,
  55.   gx_path_type_t type)
  56. {    bool do_close = (type & gx_path_type_stroke) != 0;
  57.     gs_fixed_rect rect;
  58.     gs_point scale;
  59.     double x_start = 0, y_start = 0, x_prev, y_prev;
  60.     bool first = true;
  61.     gs_path_enum cenum;
  62.     int code;
  63.  
  64.     if ( gx_path_is_rectangle(ppath, &rect) )
  65.       return (*vdev_proc(vdev, dorect))(vdev, rect.p.x, rect.p.y, rect.q.x,
  66.                         rect.q.y, type);
  67.     scale = vdev->scale;
  68.     code = (*vdev_proc(vdev, beginpath))(vdev, type);
  69.     gx_path_enum_init(&cenum, ppath);
  70.     for ( ; ; )
  71.       { fixed vs[6];
  72.         int pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
  73.         double x, y;
  74.  
  75. sw:        switch ( pe_op )
  76.           {
  77.           case 0:        /* done */
  78.         return (*vdev_proc(vdev, endpath))(vdev, type);
  79.           case gs_pe_moveto:
  80.         code = (*vdev_proc(vdev, moveto))
  81.           (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x),
  82.            (y = fixed2float(vs[1]) / scale.y), first);
  83.         if ( first )
  84.           x_start = x, y_start = y, first = false;
  85.         break;
  86.           case gs_pe_lineto:
  87.         code = (*vdev_proc(vdev, lineto))
  88.           (vdev, x_prev, y_prev, (x = fixed2float(vs[0]) / scale.x),
  89.            (y = fixed2float(vs[1]) / scale.y));
  90.         break;
  91.           case gs_pe_curveto:
  92.         code = (*vdev_proc(vdev, curveto))
  93.           (vdev, x_prev, y_prev,
  94.            fixed2float(vs[0]) / scale.x,
  95.            fixed2float(vs[1]) / scale.y,
  96.            fixed2float(vs[2]) / scale.x,
  97.            fixed2float(vs[3]) / scale.y,
  98.            (x = fixed2float(vs[4]) / scale.x),
  99.            (y = fixed2float(vs[5]) / scale.y));
  100.         break;
  101.           case gs_pe_closepath:
  102.         x = x_start, y = y_start;
  103.         if ( do_close )
  104.           { code = (*vdev_proc(vdev, closepath))
  105.               (vdev, x_prev, y_prev, x_start, y_start);
  106.             break;
  107.           }
  108.         pe_op = gx_path_enum_next(&cenum, (gs_fixed_point *)vs);
  109.         if ( pe_op != 0 )
  110.           { code = (*vdev_proc(vdev, closepath))
  111.               (vdev, x_prev, y_prev, x_start, y_start);
  112.             if ( code < 0 )
  113.               return code;
  114.             goto sw;
  115.           }
  116.         return (*vdev_proc(vdev, endpath))(vdev, type);
  117.           default:        /* can't happen */
  118.         return_error(gs_error_unknownerror);
  119.           }
  120.         if ( code < 0 )
  121.           return code;
  122.         x_prev = x, y_prev = y;
  123.       }
  124. }
  125.  
  126. int
  127. gdev_vector_dorect(gx_device_vector *vdev, fixed x0, fixed y0, fixed x1,
  128.   fixed y1, gx_path_type_t type)
  129. {    int code = (*vdev_proc(vdev, beginpath))(vdev, type);
  130.     if ( code < 0 )
  131.       return code;
  132.     code = gdev_vector_write_rectangle(vdev, x0, y0, x1, y1,
  133.                        (type & gx_path_type_stroke) != 0,
  134.                        gx_rect_x_first);
  135.     if ( code < 0 )
  136.       return code;
  137.     return (*vdev_proc(vdev, endpath))(vdev, type);
  138. }
  139.  
  140. /* ================ Utility procedures ================ */
  141.  
  142. /* Recompute the cached color values. */
  143. private void
  144. gdev_vector_load_cache(gx_device_vector *vdev)
  145. {    vdev->black =
  146.       (*dev_proc(vdev, map_rgb_color))
  147.       ((gx_device *)vdev, (gx_color_value)0, (gx_color_value)0, (gx_color_value)0);
  148.     vdev->white =
  149.       (*dev_proc(vdev, map_rgb_color))
  150.       ((gx_device *)vdev, gx_max_color_value, gx_max_color_value, gx_max_color_value);
  151. }
  152.  
  153. /* Initialize the state. */
  154. void
  155. gdev_vector_init(gx_device_vector *vdev)
  156. {    gdev_vector_reset(vdev);
  157.     vdev->scale.x = vdev->scale.y = 1.0;
  158.     vdev->in_page = false;
  159.     gdev_vector_load_cache(vdev);
  160. }
  161.  
  162. /* Reset the remembered graphics state. */
  163. void
  164. gdev_vector_reset(gx_device_vector *vdev)
  165. {    static const gs_imager_state state_initial =
  166.       { gs_imager_state_initial(1) };
  167.  
  168.     vdev->state = state_initial;
  169.     color_unset(&vdev->fill_color);
  170.     color_unset(&vdev->stroke_color);
  171.     vdev->clip_path_id =
  172.       vdev->no_clip_path_id = gs_next_ids(1);
  173. }
  174.  
  175. /* Open the output file and stream. */
  176. int
  177. gdev_vector_open_file_bbox(gx_device_vector *vdev, uint strmbuf_size,
  178.   bool bbox)
  179. {    char fmode[4];
  180.  
  181.     /* Open the file as positionable if possible. */
  182.     strcpy(fmode, "w+");
  183.     strcat(fmode, gp_fmode_binary_suffix);
  184.     vdev->file = gp_fopen(vdev->fname, fmode);
  185.     if ( vdev->file == 0 )
  186.       return_error(gs_error_invalidfileaccess);
  187.     if ( (vdev->strmbuf = gs_alloc_bytes(vdev->v_memory, strmbuf_size,
  188.                          "vector_open(strmbuf)")) == 0 ||
  189.          (vdev->strm = s_alloc(vdev->v_memory,
  190.                    "vector_open(strm)")) == 0 ||
  191.          (bbox &&
  192.           (vdev->bbox_device =
  193.            gs_alloc_struct_immovable(vdev->v_memory,
  194.                      gx_device_bbox, &st_device_bbox,
  195.                      "vector_open(bbox_device)")) == 0)
  196.        )
  197.       { if ( vdev->bbox_device )
  198.           gs_free_object(vdev->v_memory, vdev->bbox_device,
  199.                  "vector_open(bbox_device)");
  200.         vdev->bbox_device = 0;
  201.         if ( vdev->strm )
  202.           gs_free_object(vdev->v_memory, vdev->strm,
  203.                  "vector_open(strm)");
  204.         vdev->strm = 0;
  205.         if ( vdev->strmbuf )
  206.           gs_free_object(vdev->v_memory, vdev->strmbuf,
  207.                  "vector_open(strmbuf)");
  208.         vdev->strmbuf = 0;
  209.         fclose(vdev->file);
  210.         vdev->file = 0;
  211.         return_error(gs_error_VMerror);
  212.       }
  213.     vdev->strmbuf_size = strmbuf_size;
  214.     swrite_file(vdev->strm, vdev->file, vdev->strmbuf, strmbuf_size);
  215.     /*
  216.      * We don't want finalization to close the file, but we do want it
  217.      * to flush the stream buffer.
  218.      */
  219.     vdev->strm->procs.close = vdev->strm->procs.flush;
  220.     if ( vdev->bbox_device )
  221.       { gx_device_bbox_init(vdev->bbox_device, NULL);
  222.         gx_device_set_resolution((gx_device *)vdev->bbox_device,
  223.                      vdev->HWResolution[0],
  224.                      vdev->HWResolution[1]);
  225.         /* Do the right thing about upright vs. inverted. */
  226.         /* (This is dangerous in general, since the procedure */
  227.         /* might reference non-standard elements.) */
  228.         set_dev_proc(vdev->bbox_device, get_initial_matrix,
  229.              dev_proc(vdev, get_initial_matrix));
  230.         (*dev_proc(vdev->bbox_device, open_device))
  231.           ((gx_device *)vdev->bbox_device);
  232.       }
  233.     return 0;
  234. }
  235.  
  236. /* Get the current stream, calling beginpage if in_page is false. */
  237. stream *
  238. gdev_vector_stream(gx_device_vector *vdev)
  239. {    if ( !vdev->in_page )
  240.       { (*vdev_proc(vdev, beginpage))(vdev);
  241.         vdev->in_page = true;
  242.       }
  243.     return vdev->strm;
  244. }
  245.  
  246. /* Compare two drawing colors. */
  247. /* Right now we don't attempt to handle non-pure colors. */
  248. private bool
  249. drawing_color_eq(const gx_drawing_color *pdc1, const gx_drawing_color *pdc2)
  250. {    return (gx_dc_is_pure(pdc1) ?
  251.         gx_dc_is_pure(pdc2) &&
  252.         gx_dc_pure_color(pdc1) == gx_dc_pure_color(pdc2) :
  253.         gx_dc_is_null(pdc1) ?
  254.         gx_dc_is_null(pdc2) :
  255.         false);
  256. }
  257.  
  258. /* Update the logical operation. */
  259. int
  260. gdev_vector_update_log_op(gx_device_vector *vdev, gs_logical_operation_t lop)
  261. {    gs_logical_operation_t diff = lop ^ vdev->state.log_op;
  262.     if ( diff != 0 )
  263.       { int code = (*vdev_proc(vdev, setlogop))(vdev, lop, diff);
  264.         if ( code < 0 )
  265.           return code;
  266.         vdev->state.log_op = lop;
  267.       }
  268.     return 0;
  269. }
  270.  
  271. /* Update the fill color. */
  272. int
  273. gdev_vector_update_fill_color(gx_device_vector *vdev,
  274.   const gx_drawing_color *pdcolor)
  275. {    if ( !drawing_color_eq(pdcolor, &vdev->fill_color) )
  276.       { int code = (*vdev_proc(vdev, setfillcolor))(vdev, pdcolor);
  277.         if ( code < 0 )
  278.           return code;
  279.         vdev->fill_color = *pdcolor;
  280.       }
  281.     return 0;
  282. }
  283.  
  284. /* Update the state for filling a region. */
  285. private int
  286. update_fill(gx_device_vector *vdev, const gx_drawing_color *pdcolor,
  287.   gs_logical_operation_t lop)
  288. {    int code = gdev_vector_update_fill_color(vdev, pdcolor);
  289.     if ( code < 0 )
  290.       return code;
  291.     return gdev_vector_update_log_op(vdev, lop);
  292. }
  293.  
  294. /* Bring state up to date for filling. */
  295. int
  296. gdev_vector_prepare_fill(gx_device_vector *vdev, const gs_imager_state *pis,
  297.   const gx_fill_params *params, const gx_drawing_color *pdcolor)
  298. {    if ( params->flatness != vdev->state.flatness )
  299.       { int code = (*vdev_proc(vdev, setflat))(vdev, params->flatness);
  300.         if ( code < 0 )
  301.           return code;
  302.         vdev->state.flatness = params->flatness;
  303.       }
  304.     return update_fill(vdev, pdcolor, pis->log_op);
  305. }
  306.  
  307. /* Compare two dash patterns. */
  308. private bool
  309. dash_pattern_eq(const float *stored, const gx_dash_params *set, floatp scale)
  310. {    int i;
  311.     for ( i = 0; i < set->pattern_size; ++i )
  312.       if ( stored[i] != (float)(set->pattern[i] * scale) )
  313.         return false;
  314.     return true;
  315. }
  316.  
  317. /* Bring state up to date for stroking. */
  318. int
  319. gdev_vector_prepare_stroke(gx_device_vector *vdev, const gs_imager_state *pis,
  320.   const gx_stroke_params *params, const gx_drawing_color *pdcolor,
  321.   floatp scale)
  322. {    int pattern_size = pis->line_params.dash.pattern_size;
  323.     float dash_offset = pis->line_params.dash.offset * scale;
  324.     float half_width = pis->line_params.half_width * scale;
  325.  
  326.     if ( pattern_size > max_dash )
  327.       return_error(gs_error_limitcheck);
  328.     if ( dash_offset != vdev->state.line_params.dash.offset ||
  329.          pattern_size != vdev->state.line_params.dash.pattern_size ||
  330.          (pattern_size != 0 &&
  331.           !dash_pattern_eq(vdev->dash_pattern, &pis->line_params.dash,
  332.                    scale))
  333.        )
  334.       { float pattern[max_dash];
  335.         int i, code;
  336.  
  337.         for ( i = 0; i < pattern_size; ++i )
  338.           pattern[i] = pis->line_params.dash.pattern[i] * scale;
  339.         code = (*vdev_proc(vdev, setdash))
  340.           (vdev, pattern, pattern_size, dash_offset);
  341.         if ( code < 0 )
  342.           return code;
  343.         memcpy(vdev->dash_pattern, pattern, pattern_size * sizeof(float));
  344.         vdev->state.line_params.dash.pattern_size = pattern_size;
  345.         vdev->state.line_params.dash.offset = dash_offset;
  346.       }
  347.     if ( params->flatness != vdev->state.flatness )
  348.       { int code = (*vdev_proc(vdev, setflat))(vdev, params->flatness);
  349.         if ( code < 0 )
  350.           return code;
  351.         vdev->state.flatness = params->flatness;
  352.       }
  353.     if ( half_width != vdev->state.line_params.half_width )
  354.       { int code = (*vdev_proc(vdev, setlinewidth))
  355.           (vdev, pis->line_params.half_width * 2);
  356.         if ( code < 0 )
  357.           return code;
  358.         vdev->state.line_params.half_width = half_width;
  359.       }
  360.     if ( pis->line_params.miter_limit != vdev->state.line_params.miter_limit )
  361.       { int code = (*vdev_proc(vdev, setmiterlimit))
  362.           (vdev, pis->line_params.miter_limit);
  363.         if ( code < 0 )
  364.           return code;
  365.         gx_set_miter_limit(&vdev->state.line_params,
  366.                    pis->line_params.miter_limit);
  367.       }
  368.     if ( pis->line_params.cap != vdev->state.line_params.cap )
  369.       { int code = (*vdev_proc(vdev, setlinecap))
  370.           (vdev, pis->line_params.cap);
  371.         if ( code < 0 )
  372.           return code;
  373.         vdev->state.line_params.cap = pis->line_params.cap;
  374.       }
  375.     if ( pis->line_params.join != vdev->state.line_params.join )
  376.       { int code = (*vdev_proc(vdev, setlinejoin))
  377.           (vdev, pis->line_params.join);
  378.         if ( code < 0 )
  379.           return code;
  380.         vdev->state.line_params.join = pis->line_params.join;
  381.       }
  382.     { int code = gdev_vector_update_log_op(vdev, pis->log_op);
  383.       if ( code < 0 )
  384.         return code;
  385.       }
  386.     if ( !drawing_color_eq(pdcolor, &vdev->stroke_color) )
  387.       { int code = (*vdev_proc(vdev, setstrokecolor))(vdev, pdcolor);
  388.         if ( code < 0 )
  389.           return code;
  390.         vdev->stroke_color = *pdcolor;
  391.       }
  392.     return 0;
  393. }
  394.  
  395. /* Write a polygon as part of a path. */
  396. /* May call beginpath, moveto, lineto, closepath, endpath. */
  397. int
  398. gdev_vector_write_polygon(gx_device_vector *vdev, const gs_fixed_point *points,
  399.   uint count, bool close, gx_path_type_t type)
  400. {    int code = 0;
  401.  
  402.     if ( type != gx_path_type_none &&
  403.          (code = (*vdev_proc(vdev, beginpath))(vdev, type)) < 0
  404.        )
  405.       return code;
  406.     if ( count > 0 )
  407.       { double x = fixed2float(points[0].x) / vdev->scale.x,
  408.           y = fixed2float(points[0].y) / vdev->scale.y;
  409.         double x_start = x, y_start = y, x_prev, y_prev;
  410.         uint i;
  411.  
  412.         code = (*vdev_proc(vdev, moveto))
  413.           (vdev, 0.0, 0.0, x, y, true);
  414.         if ( code >= 0 )
  415.           for ( i = 1; i < count && code >= 0; ++i )
  416.         { x_prev = x, y_prev = y;
  417.         code = (*vdev_proc(vdev, lineto))
  418.           (vdev, x_prev, y_prev,
  419.            (x = fixed2float(points[i].x) / vdev->scale.x),
  420.            (y = fixed2float(points[i].y) / vdev->scale.y));
  421.         }
  422.         if ( code >= 0 && close )
  423.           code = (*vdev_proc(vdev, closepath))
  424.             (vdev, x, y, x_start, y_start);
  425.       }
  426.     return (code >= 0 && type != gx_path_type_none ?
  427.         (*vdev_proc(vdev, endpath))(vdev, type) : code);
  428. }
  429.  
  430. /* Write a rectangle as part of a path. */
  431. /* May call moveto, lineto, closepath. */
  432. int
  433. gdev_vector_write_rectangle(gx_device_vector *vdev, fixed x0, fixed y0,
  434.   fixed x1, fixed y1, bool close, gx_rect_direction_t direction)
  435. {    gs_fixed_point points[4];
  436.  
  437.     points[0].x = x0, points[0].y = y0;
  438.     points[2].x = x1, points[2].y = y1;
  439.     if ( direction == gx_rect_x_first )
  440.       points[1].x = x1, points[1].y = y0,
  441.         points[3].x = x0, points[3].y = y1;
  442.     else
  443.       points[1].x = x0, points[1].y = y1,
  444.         points[3].x = x1, points[3].y = y0;
  445.     return gdev_vector_write_polygon(vdev, points, 4, close,
  446.                      gx_path_type_none);
  447. }
  448.  
  449. /* Write a clipping path by calling the path procedures. */
  450. int
  451. gdev_vector_write_clip_path(gx_device_vector *vdev, const gx_clip_path *pcpath)
  452. {    const gx_clip_rect *prect;
  453.     gx_clip_rect page_rect;
  454.     int code;
  455.  
  456.     if ( pcpath == 0 )
  457.       { /* There's no special provision for initclip. */
  458.         /* Write a rectangle that covers the entire page. */
  459.         page_rect.xmin = page_rect.ymin = 0;
  460.         page_rect.xmax = vdev->width;
  461.         page_rect.ymax = vdev->height;
  462.         page_rect.next = 0;
  463.         prect = &page_rect;
  464.       }
  465.     else if ( pcpath->segments_valid )
  466.       return (*vdev_proc(vdev, dopath))(vdev, &pcpath->path,
  467.                         gx_path_type_clip);
  468.     else
  469.       { prect = pcpath->list.head;
  470.         if ( prect == 0 )
  471.           prect = &pcpath->list.single;
  472.       }
  473.     /* Write out the rectangles. */
  474.     code = (*vdev_proc(vdev, beginpath))(vdev, gx_path_type_clip);
  475.     for ( ; code >= 0 && prect != 0; prect = prect->next )
  476.       if ( prect->xmax > prect->xmin && prect->ymax > prect->ymin )
  477.         code = gdev_vector_write_rectangle
  478.           (vdev, int2fixed(prect->xmin), int2fixed(prect->ymin),
  479.            int2fixed(prect->xmax), int2fixed(prect->ymax),
  480.            false, gx_rect_x_first);
  481.     if ( code >= 0 )
  482.       code = (*vdev_proc(vdev, endpath))(vdev, gx_path_type_clip);
  483.     return code;
  484. }
  485.  
  486. /* Update the clipping path if needed. */
  487. int
  488. gdev_vector_update_clip_path(gx_device_vector *vdev,
  489.   const gx_clip_path *pcpath)
  490. {    if ( pcpath )
  491.       { if ( pcpath->id != vdev->clip_path_id )
  492.           { int code = gdev_vector_write_clip_path(vdev, pcpath);
  493.             if ( code < 0 )
  494.           return code;
  495.         vdev->clip_path_id = pcpath->id;
  496.           }
  497.       }
  498.     else
  499.       { if ( vdev->clip_path_id != vdev->no_clip_path_id )
  500.           { int code = gdev_vector_write_clip_path(vdev, NULL);
  501.             if ( code < 0 )
  502.           return code;
  503.         vdev->clip_path_id = vdev->no_clip_path_id;
  504.           }
  505.       }
  506.     return 0;
  507. }
  508.  
  509. /* Close the output file and stream. */
  510. void
  511. gdev_vector_close_file(gx_device_vector *vdev)
  512. {    gs_free_object(vdev->v_memory, vdev->bbox_device,
  513.                "vector_close(bbox_device)");
  514.     vdev->bbox_device = 0;
  515.     sclose(vdev->strm);
  516.     gs_free_object(vdev->v_memory, vdev->strm, "vector_close(strm)");
  517.     vdev->strm = 0;
  518.     gs_free_object(vdev->v_memory, vdev->strmbuf, "vector_close(strmbuf)");
  519.     vdev->strmbuf = 0;
  520.     fclose(vdev->file);    /* we prevented sclose from doing this */
  521.     vdev->file = 0;
  522. }
  523.  
  524. /* ---------------- Image enumeration ---------------- */
  525.  
  526. /* Initialize for enumerating an image. */
  527. int
  528. gdev_vector_begin_image(gx_device_vector *vdev,
  529.   const gs_imager_state *pis, const gs_image_t *pim,
  530.   gs_image_format_t format, const gs_int_rect *prect,
  531.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath,
  532.   gs_memory_t *mem, gdev_vector_image_enum_t *pie)
  533. {    const gs_color_space *pcs = pim->ColorSpace;
  534.     int num_components;
  535.     int bits_per_pixel;
  536.     int code;
  537.  
  538.     if ( pim->ImageMask )
  539.       bits_per_pixel = num_components = 1;
  540.     else
  541.       num_components = gs_color_space_num_components(pcs),
  542.         bits_per_pixel = pim->BitsPerComponent;
  543.     switch ( format )
  544.       {
  545.       case gs_image_format_chunky:
  546.         pie->num_planes = 1;
  547.         pie->bits_per_pixel = bits_per_pixel * num_components;
  548.         break;
  549.       case gs_image_format_component_planar:
  550.         pie->num_planes = num_components;
  551.         pie->bits_per_pixel = bits_per_pixel;
  552.         break;
  553.       default:
  554.         return_error(gs_error_rangecheck);
  555.       }
  556.     pie->default_info = 0;
  557.     pie->bbox_info = 0;
  558.     if ( (code = gdev_vector_update_log_op(vdev, pis->log_op)) < 0 ||
  559.          (code = gdev_vector_update_clip_path(vdev, pcpath)) < 0 ||
  560.          ((pim->ImageMask ||
  561.            (pim->CombineWithColor && rop3_uses_T(pis->log_op))) &&
  562.           (code = gdev_vector_update_fill_color(vdev, pdcolor)) < 0) ||
  563.          (vdev->bbox_device &&
  564.           (code = (*dev_proc(vdev->bbox_device, begin_image))
  565.            ((gx_device *)vdev->bbox_device, pis, pim, format, prect,
  566.         pdcolor, pcpath, mem, &pie->bbox_info)) < 0)
  567.        )
  568.       return code;
  569.     pie->memory = mem;
  570.     if ( prect )
  571.       pie->width = prect->q.x - prect->p.x,
  572.         pie->height = prect->q.y - prect->p.y;
  573.     else
  574.       pie->width = pim->Width, pie->height = pim->Height;
  575.     pie->bits_per_row = pie->width * pie->bits_per_pixel;
  576.     pie->y = 0;
  577.     return 0;
  578. }
  579.  
  580. /* End an image, optionally supplying any necessary blank padding rows. */
  581. /* Return 0 if we used the default implementation, 1 if not. */
  582. int
  583. gdev_vector_end_image(gx_device_vector *vdev,
  584.   gdev_vector_image_enum_t *pie, bool draw_last, gx_color_index pad)
  585. {    int code;
  586.  
  587.     if ( pie->default_info )
  588.       { code = gx_default_end_image((gx_device *)vdev, pie->default_info,
  589.                     draw_last);
  590.         if ( code >= 0 )
  591.           code = 0;
  592.       }
  593.     else
  594.       { /* Fill out to the full image height. */
  595.         if ( pie->y < pie->height && pad != gx_no_color_index )
  596.           { uint bytes_per_row =  (pie->bits_per_row + 7) >> 3;
  597.             byte *row = gs_alloc_bytes(pie->memory, bytes_per_row,
  598.                        "gdev_vector_end_image(fill)");
  599.  
  600.         if ( row == 0 )
  601.           return_error(gs_error_VMerror);
  602.         /****** FILL VALUE IS WRONG ******/
  603.         memset(row, (byte)pad, bytes_per_row);
  604.         for ( ; pie->y < pie->height; pie->y++ )
  605.           (*dev_proc(vdev, image_data))((gx_device *)vdev, pie,
  606.                         (const byte **)&row, 0,
  607.                         bytes_per_row, 1);
  608.         gs_free_object(pie->memory, row,
  609.                    "gdev_vector_end_image(fill)");
  610.           }
  611.         code = 1;
  612.       }
  613.     if ( vdev->bbox_device )
  614.       { int bcode = (*dev_proc(vdev->bbox_device, end_image))
  615.           ((gx_device *)vdev->bbox_device, pie->bbox_info, draw_last);
  616.         if ( bcode < 0 )
  617.           code = bcode;
  618.       }
  619.     gs_free_object(pie->memory, pie, "pclxl_end_image");
  620.     return code;
  621. }
  622.  
  623. /* ================ Device procedures ================ */
  624.  
  625. #define vdev ((gx_device_vector *)dev)
  626.  
  627. /* Get parameters. */
  628. int
  629. gdev_vector_get_params(gx_device *dev, gs_param_list *plist)
  630. {    int code = gx_default_get_params(dev, plist);
  631.     int ecode;
  632.     gs_param_string ofns;
  633.  
  634.     if ( code < 0 )
  635.       return code;
  636.     ofns.data = (const byte *)vdev->fname,
  637.       ofns.size = strlen(vdev->fname),
  638.       ofns.persistent = false;
  639.     if ( (ecode = param_write_string(plist, "OutputFile", &ofns)) < 0 )
  640.       return ecode;
  641.     return code;
  642. }
  643.  
  644. /* Put parameters. */
  645. int
  646. gdev_vector_put_params(gx_device *dev, gs_param_list *plist)
  647. {    int ecode = 0;
  648.     int code;
  649.     gs_param_name param_name;
  650.     gs_param_string ofns;
  651.  
  652.     switch ( code = param_read_string(plist, (param_name = "OutputFile"), &ofns) )
  653.     {
  654.     case 0:
  655.         if ( ofns.size > fname_size )
  656.           ecode = gs_error_limitcheck;
  657.         else
  658.           break;
  659.         goto ofe;
  660.     default:
  661.         ecode = code;
  662. ofe:        param_signal_error(plist, param_name, ecode);
  663.     case 1:
  664.         ofns.data = 0;
  665.         break;
  666.     }
  667.  
  668.     if ( ecode < 0 )
  669.       return ecode;
  670.     { bool open = dev->is_open;
  671.       /* Don't let gx_default_put_params close the device. */
  672.       dev->is_open = false;
  673.       code = gx_default_put_params(dev, plist);
  674.       dev->is_open = open;
  675.     }
  676.     if ( code < 0 )
  677.       return code;
  678.  
  679.     if ( ofns.data != 0 &&
  680.          bytes_compare(ofns.data, ofns.size,
  681.                (const byte *)vdev->fname, strlen(vdev->fname))
  682.        )
  683.       {    memcpy(vdev->fname, ofns.data, ofns.size);
  684.         vdev->fname[ofns.size] = 0;
  685.         if ( vdev->file != 0 )
  686.           { gdev_vector_close_file(vdev);
  687.             return gdev_vector_open_file(vdev, vdev->strmbuf_size);
  688.           }
  689.       }
  690.  
  691.     gdev_vector_load_cache(vdev); /* in case color mapping changed */
  692.     return 0;
  693. }
  694.  
  695. /* ---------------- Defaults ---------------- */
  696.  
  697. int
  698. gdev_vector_fill_rectangle(gx_device *dev, int x, int y, int w, int h,
  699.   gx_color_index color)
  700. {    gx_drawing_color dcolor;
  701.  
  702.     /* Ignore the initial fill with white. */
  703.     if ( !vdev->in_page && color == vdev->white )
  704.       return 0;
  705.     color_set_pure(&dcolor, color);
  706.     { int code = update_fill(vdev, &dcolor, rop3_T);
  707.       if ( code < 0 )
  708.         return code;
  709.     }
  710.     if ( vdev->bbox_device )
  711.       { int code = (*dev_proc(vdev->bbox_device, fill_rectangle))
  712.           ((gx_device *)vdev->bbox_device, x, y, w, h, color);
  713.         if ( code < 0 )
  714.           return code;
  715.       }
  716.     return (*vdev_proc(vdev, dorect))(vdev, int2fixed(x), int2fixed(y),
  717.                       int2fixed(x + w), int2fixed(y + h),
  718.                       gx_path_type_fill);
  719. }
  720.  
  721. int
  722. gdev_vector_fill_path(gx_device *dev, const gs_imager_state *pis,
  723.   gx_path *ppath, const gx_fill_params *params,
  724.   const gx_device_color *pdevc, const gx_clip_path *pcpath)
  725. {    int code = gdev_vector_prepare_fill(vdev, pis, params, pdevc);
  726.  
  727.     if ( code < 0 )
  728.       return code;
  729.     code = gdev_vector_update_clip_path(vdev, pcpath);
  730.     if ( code < 0 )
  731.       return code;
  732.     if ( vdev->bbox_device )
  733.       { code = (*dev_proc(vdev->bbox_device, fill_path))
  734.           ((gx_device *)vdev->bbox_device, pis, ppath, params,
  735.            pdevc, pcpath);
  736.         if ( code < 0 )
  737.           return code;
  738.       }
  739.     return (*vdev_proc(vdev, dopath))(vdev, ppath,
  740.                       (params->rule > 0 ?
  741.                        gx_path_type_even_odd :
  742.                        gx_path_type_winding_number) |
  743.                       gx_path_type_fill);
  744. }
  745.  
  746. int
  747. gdev_vector_stroke_path(gx_device *dev, const gs_imager_state *pis,
  748.   gx_path *ppath, const gx_stroke_params *params,
  749.   const gx_drawing_color *pdcolor, const gx_clip_path *pcpath)
  750. {    int code;
  751.  
  752.     /****** HANDLE SCALE ******/
  753.     code = gdev_vector_prepare_stroke(vdev, pis, params, pdcolor,
  754.                       dev->HWResolution[0]);
  755.     if ( code < 0 )
  756.       return code;
  757.     code = gdev_vector_update_clip_path(vdev, pcpath);
  758.     if ( code < 0 )
  759.       return code;
  760.     if ( vdev->bbox_device )
  761.       { code = (*dev_proc(vdev->bbox_device, stroke_path))
  762.           ((gx_device *)vdev->bbox_device, pis, ppath, params,
  763.            pdcolor, pcpath);
  764.         if ( code < 0 )
  765.           return code;
  766.       }
  767.     return (*vdev_proc(vdev, dopath))(vdev, ppath, gx_path_type_stroke);
  768. }
  769.  
  770. int
  771. gdev_vector_fill_trapezoid(gx_device *dev, const gs_fixed_edge *left,
  772.   const gs_fixed_edge *right, fixed ybot, fixed ytop, bool swap_axes,
  773.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  774. {    fixed xl = left->start.x;
  775.     fixed wl = left->end.x - xl;
  776.     fixed yl = left->start.y;
  777.     fixed hl = left->end.y - yl;
  778.     fixed xr = right->start.x;
  779.     fixed wr = right->end.x - xr;
  780.     fixed yr = right->start.y;
  781.     fixed hr = right->end.y - yr;
  782.     fixed x0l = xl + fixed_mult_quo(wl, ybot - yl, hl);
  783.     fixed x1l = xl + fixed_mult_quo(wl, ytop - yl, hl);
  784.     fixed x0r = xr + fixed_mult_quo(wr, ybot - yr, hr);
  785.     fixed x1r = xr + fixed_mult_quo(wr, ytop - yr, hr);
  786. #define y0 ybot
  787. #define y1 ytop
  788.     gs_fixed_point points[4];
  789.  
  790.     if ( swap_axes )
  791.       points[0].y = x0l, points[1].y = x0r,
  792.         points[0].x = points[1].x = y0,
  793.         points[2].y = x1r, points[3].y = x1l,
  794.         points[2].x = points[3].x = y1;
  795.     else
  796.       points[0].x = x0l, points[1].x = x0r,
  797.         points[0].y = points[1].y = y0,
  798.         points[2].x = x1r, points[3].x = x1l,
  799.         points[2].y = points[3].y = y1;
  800. #undef y0
  801. #undef y1
  802.     if ( vdev->bbox_device )
  803.       { int code = (*dev_proc(vdev->bbox_device, fill_trapezoid))
  804.           ((gx_device *)vdev->bbox_device, left, right, ybot, ytop,
  805.            swap_axes, pdevc, lop);
  806.         if ( code < 0 )
  807.           return code;
  808.       }
  809.     return gdev_vector_write_polygon(vdev, points, 4, true,
  810.                      gx_path_type_fill);
  811. }
  812.  
  813. int
  814. gdev_vector_fill_parallelogram(gx_device *dev,
  815.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  816.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  817. {    fixed pax = px + ax, pay = py + ay;
  818.     int code = update_fill(vdev, pdevc, lop);
  819.     gs_fixed_point points[4];
  820.  
  821.     if ( code < 0 )
  822.       return code;
  823.     if ( vdev->bbox_device )
  824.       { code = (*dev_proc(vdev->bbox_device, fill_parallelogram))
  825.           ((gx_device *)vdev->bbox_device, px, py, ax, ay, bx, by,
  826.            pdevc, lop);
  827.         if ( code < 0 )
  828.           return code;
  829.       }
  830.     points[0].x = px, points[0].y = py;
  831.     points[1].x = pax, points[0].y = pay;
  832.     points[2].x = pax + bx, points[2].y = pay + by;
  833.     points[3].x = px + bx, points[3].y = py + by;
  834.     return gdev_vector_write_polygon(vdev, points, 4, true,
  835.                      gx_path_type_fill);
  836. }
  837.  
  838. int
  839. gdev_vector_fill_triangle(gx_device *dev,
  840.   fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  841.   const gx_device_color *pdevc, gs_logical_operation_t lop)
  842. {    int code = update_fill(vdev, pdevc, lop);
  843.     gs_fixed_point points[3];
  844.  
  845.     if ( code < 0 )
  846.       return code;
  847.     if ( vdev->bbox_device )
  848.       { code = (*dev_proc(vdev->bbox_device, fill_triangle))
  849.           ((gx_device *)vdev->bbox_device, px, py, ax, ay, bx, by,
  850.            pdevc, lop);
  851.         if ( code < 0 )
  852.           return code;
  853.       }
  854.     points[0].x = px, points[0].y = py;
  855.     points[1].x = px + ax, points[1].y = py + ay;
  856.     points[2].x = px + bx, points[2].y = py + by;
  857.     return gdev_vector_write_polygon(vdev, points, 3, true,
  858.                      gx_path_type_fill);
  859. }
  860.  
  861. #undef vdev
  862.